﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EntityBinder.Interface;

namespace EntityBinder
{
	public class EntityElement : IEntityElement
	{
		public string Identifier { get; set; }

		public bool Optional { get; set; }

		public IBinder Binder { get; set; }

		public IMemberAccess Member { get; set; }

		private List<IEntityElement> m_children = new List<IEntityElement>();
		public IEnumerable<IEntityElement> Children 
		{
			get { return m_children; }
		}

		public EntityElement()
		{
			Identifier = "";
			Optional = false;
			Binder = null;
			Member = null;
		}

		public EntityElement(string _identifier) : this()
		{
			Identifier = _identifier;
		}

		public EntityElement(string _identifier, IBinder _binder) : this(_identifier)
		{
			Binder = _binder;
		}

		public EntityElement(string _identifier, IBinder _binder, IMemberAccess _member) : this(_identifier, _binder)
		{
			Member = _member;
		}

		public void AddChild(IEntityElement _child)
		{
			m_children.Add(_child);
		}

		public void AddChildren(params IEntityElement[] _children)
		{
			foreach(IEntityElement e in _children)
			{
				m_children.Add(e);
			}
		}

		public void RemoveChild(IEntityElement _child)
		{
			m_children.Remove(_child);
		}

		public void RemoveChild(int _childIndex)
		{
			m_children.RemoveAt(_childIndex);
		}

		public void RemoveAllChildren()
		{
			m_children.Clear();
		}

		public object Read(object _source, string _contentValue)
		{
			return Binder.Read(_source, _contentValue, Member);
		}

		public void Write(object _source, IElementWriter _writer)
		{
			if(Binder.BinderType == BinderType.VALUE)
			{
				_writer.WriteElementStart(this.Identifier);
				_writer.WriteElementValue(Binder.Write(_source, Member));
				_writer.WriteElementEnd();
			}
			else if(Binder.BinderType == BinderType.CONTAINER)
			{
				_writer.WriteObjectStart(this.Identifier);
				object childData = (Member == null) ? _source : Member.Get(_source);
				foreach(IEntityElement child in m_children)
				{
					child.Write(childData, _writer);
				}
				_writer.WriteObjectEnd();
			}
			else if(Binder.BinderType == BinderType.ARRAY_OF_VALUE)
			{
				_writer.WriteArrayStart(this.Identifier);
				foreach(object o in (Member.Get(_source) as IEnumerable))
				{
					_writer.WriteElementStart(this.Identifier);
					_writer.WriteElementValue(Binder.Write(o, null));
					_writer.WriteElementEnd();
				}
				_writer.WriteArrayEnd();
			}
			else if(Binder.BinderType == BinderType.ARRAY_OF_CONTAINER)
			{
				_writer.WriteArrayStart(this.Identifier);
				foreach (object o in (Member.Get(_source) as IEnumerable))
				{
					_writer.WriteObjectStart(this.Identifier);
					foreach (IEntityElement child in m_children)
					{
						child.Write(o, _writer);
					}
					_writer.WriteObjectEnd();
				}
				_writer.WriteArrayEnd();
			}
		}
	}
}
